package com.l.Thread.Lock;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * ReentrantReadWriteLock(读写锁)
 * 1.创建一个ReentrantReadWriteLock对象
 * 2.调用ReentrantReadWriteLock对象中的readLock()和writeLock()方法，
 *   返回一个ReentrantReadWriteLock.ReadLock内部类的对象
 * 3.调用ReadLock中的Lock()和unLock(),分别实现对读和写操作的锁
 *
 * 注：对于读写锁来说：读和读操作是不互斥的
 *                  写和读是互斥的
 *                  写和写是互斥的
 * 使用：读操作较多的时候，读写锁既保证了线程的安全也保证了线程的效率
 *
 * @author Mc.Chai
 * @program: Java基础
 * @create 2021-11-17-9:30 09:30
 */
public class TestReentrantReadWriteLock {
    public static void main(String[] args) {
        /**
         * 1.创建一个进行读写操作的类
         * 2.创建一个ExecutorService线程池并给定线程的数量
         * 3.创建两个Callable的任务，分别进行读任务和写任务，用于线程池任务的提交（也可以使用Runnable进行实现）
         * 4.利用for循环进行多个任务的同时提交，同时提交多个任务
         * 5.利用while循环的判断，使用isTerminated()来判断是否线程池已经完成任务
         * 6.计算整个读写操作的整体时间
         *
         * 注：整个过程的执行时间短暂，在读和写操作时分别设置了1秒的sleep,整个过程中，执行读操作只需要总体1秒钟而写操作需要
         *    根据写操作的次数来决定的
         *
         * */
        MyClass myClass=new MyClass();
        ExecutorService es= Executors.newFixedThreadPool(20);
        //写的操作任务
        Callable writeTask=new Callable<>() {
            @Override
            public Object call() throws Exception {
                myClass.setValue(11);
                return null;
            }
        };
        //读的操作任务
        Callable readTask=new Callable<>() {
            @Override
            public Object call() throws Exception {
                myClass.getValue();
                return null;
            }
        };
        //开始的时间
        long start=System.currentTimeMillis();
        //并发的写
        for (int i = 0; i < 2; i++) {
            es.submit(writeTask);
        }
        //并发的读取
        for (int i = 0; i < 18; i++) {
            es.submit(readTask);

        }
        es.shutdown();//停止线程池（不再接受新的任务，将现有的任务全部执行完毕）
        while(true){
            if (es.isTerminated()){ //任务全部完成返回true,否则返回false
                break;
            }
        }
        System.out.println(System.currentTimeMillis()-start);
    }
}
class MyClass{
    private int value;
    /**
     * readLock和WriteLock都是使用的是ReentrantReadWriteLock中的锁，所以在读写并发执行是互斥的
     * */
    ReentrantReadWriteLock rwl=new ReentrantReadWriteLock();
    ReentrantReadWriteLock.ReadLock readLock=rwl.readLock();        //读锁
    ReentrantReadWriteLock.WriteLock writeLock=rwl.writeLock();     //写锁

    //读操作
    public int getValue() {
        readLock.lock();
        try {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return value;
        } finally {
            readLock.unlock();
        }
    }


    //写操作
    public void setValue(int value) {
        writeLock.lock();
        try {
            this.value = value;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } finally {
            writeLock.unlock();
        }
    }
}
